use crate::db::{dao, po};
use crate::service::Error;
use sea_orm::IntoSimpleExpr;
use std::sync::Arc;

#[async_trait::async_trait]
pub trait SegmentService: Send + Sync {
    async fn add_list(
        &self,
        segment_list_id: &str,
        endpoint_id_list: &[String],
    ) -> Result<(), Error>;

    async fn list(&self, segment_list_id: &str) -> Result<Vec<String>, Error>;

    async fn delete_list(&self, segment_list_id: &str) -> Result<(), Error>;
}

pub struct DefaultSegmentService {
    segment_dao: Arc<dyn dao::segment::SegmentDao>,
}

impl DefaultSegmentService {
    pub fn new(segment_dao: Arc<dyn dao::segment::SegmentDao>) -> Self {
        DefaultSegmentService { segment_dao }
    }
}

#[async_trait::async_trait]
impl SegmentService for DefaultSegmentService {
    async fn add_list(
        &self,
        segment_list_id: &str,
        endpoint_id_list: &[String],
    ) -> Result<(), Error> {
        for (i, endpoint_id) in endpoint_id_list.iter().enumerate() {
            if i >= wanmesh_common::net::router::SEGMENT_LIST_LENGTH_MAX {
                break;
            }

            self.segment_dao
                .insert(po::segment::ActiveModel {
                    id: Default::default(),
                    segment_list_id: po::ActiveValue::Set(segment_list_id.to_string()),
                    index: po::ActiveValue::Set(i as u32),
                    endpoint_id: po::ActiveValue::Set(endpoint_id.clone()),
                    create_timestamp_millis: Default::default(),
                    update_timestamp_millis: Default::default(),
                })
                .await?;
        }

        Ok(())
    }

    async fn list(&self, segment_list_id: &str) -> Result<Vec<String>, Error> {
        let po_list = self
            .segment_dao
            .find(dao::FindParams {
                filter: dao::segment::Filter {
                    segment_list_id: Some(segment_list_id.to_string()),
                    ..Default::default()
                },
                limit: Some(wanmesh_common::net::router::SEGMENT_LIST_LENGTH_MAX as u64),
                order_by: Some(dao::OrderBy {
                    column: po::segment::Column::Index.into_simple_expr(),
                    order: sea_orm::Order::Asc,
                }),
                ..Default::default()
            })
            .await?;

        let list = po_list
            .into_iter()
            .map(|po| po.endpoint_id)
            .collect::<Vec<_>>();
        Ok(list)
    }

    async fn delete_list(&self, segment_list_id: &str) -> Result<(), Error> {
        self.segment_dao
            .delete(dao::segment::Filter {
                segment_list_id: Some(segment_list_id.to_string()),
                ..Default::default()
            })
            .await?;
        Ok(())
    }
}
